#!/usr/bin/env perl
#
# Use the "connect" trick to find out my IP address.
# Note that the destination address here does not
# actually matter, we will never send any data to it.
# We use Google's public DNS server, since, it doesn't
# matter.

use strict;
use warnings;
import IO::Socket::INET6;
# For older Perl versions AF_INET6 is defined in the Socket6 package. For newer
# Perl versions all IPv6 functionality we need is defined in the Socket package.
if (eval "use Socket6 qw(AF_INET6 inet_ntop inet_pton pack_sockaddr_in6
                             sockaddr_in6)") {
    use Socket qw(AF_INET SOCK_DGRAM pack_sockaddr_in sockaddr_in);
} else {
    use Socket qw(AF_INET AF_INET6 SOCK_DGRAM inet_ntop inet_pton
		  pack_sockaddr_in pack_sockaddr_in6 sockaddr_in sockaddr_in6);
}


my $v6 = defined($ARGV[0]) && $ARGV[0] eq "ipv6";
my ($af, $dest, $noaddr);
if ($v6) {
    $af = AF_INET6;
    $dest = '2001:4860:4860::8888';
    $noaddr = '::';
 } else {
    $af = AF_INET;
    $dest = '8.8.8.8';
    $noaddr = '0.0.0.0';
}
socket(my $sock, $af, SOCK_DGRAM, 0) or die "socket creation failed: $!";
my $myip;
if ($v6) {
    connect($sock, pack_sockaddr_in6(53, inet_pton($af, $dest)));
    my ($port, $ip6_address) = sockaddr_in6(getsockname($sock));
    socket(my $sock2, $af, SOCK_DGRAM, 0);
    my $i = 1;
    while (1) {
	bind($sock2, sockaddr_in6(0, $ip6_address, $i)) && last;
	$i++;
    }
    $myip = inet_ntop($af, $ip6_address);
    exit 1 if $myip eq $noaddr;
    $myip = $myip . '%' . $i;
} else {
    connect($sock, pack_sockaddr_in(53, inet_pton($af, $dest)));
    my ($port, $myaddr) = sockaddr_in(getsockname($sock));
    $myip = inet_ntop($af, $myaddr);
    exit 1 if $myip eq $noaddr;
}
print $myip, "\n";
exit 0;
